package algorithm;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import enumMsg.ProState;
import pojo.ProcessPojo;

public class RoundRobin {
	//时间片轮转算法
	/*
	 * 1.模拟进程启动,则需要模拟初始化出多个进程。(10个）
	 * 2.为进程设置一样的时间片大小
	 * 3.每个进程默认状态为就绪状态
	 * 4.运行就绪队列中对首的进程
	 * 5.当队首进程运行完毕或者用完了时间片,将该进程的needtime减去对应大小，同时cpuTime加上对应大小，并且将其放到队尾
	 * 6.重复4、5过程直到就绪队列为空即模拟完毕
	 */
	private LinkedList<ProcessPojo>readyQueue;//就绪队列
	
	private HashSet<ProcessPojo>runSet;//运行时队列
	
	


	public HashSet<ProcessPojo> getRunSet() {
		return runSet;
	}

	public void setRunSet(HashSet<ProcessPojo> runSet) {
		this.runSet = runSet;
	}


	private long timeSlice;//时间片大小
	
	public void go() {
		System.out.println("现在开始模拟...10个进程,时间片大小为  "+this.timeSlice);
		this.init(10);
		System.out.println("初始化完毕");
		this.startMock();
	}
	
	public void init(int n) {
		/*
		 * 初始化
		 * 1.模拟进程启动,则需要模拟初始化出多个进程。(n个）
		 * 2.为进程设置一样的时间片大小
		 * 3.每个进程默认状态为就绪状态
		 */
		this.readyQueue=new LinkedList<>();
		this.runSet=new HashSet<>();
		for(int i=0;i<n;i++) {
			ProcessPojo pcb=new ProcessPojo();
			pcb.setCpuTime(0);//初始化为0
			pcb.setName("进程-"+(i+1));//初始化进程名
			pcb.setTimeSlice(this.timeSlice);//初始化时间片
			pcb.setState(ProState.READY.getState());//初始化为就绪状态
			Random random=new Random();
			
			pcb.setNeedTime(random.nextInt(9)+1);//设置需要的时间片(随机数)
			this.readyQueue.add(pcb);
		}
	}public void runMock() {
		/*
		 * 开始模拟
		 * 4.运行就绪队列中对首的进程
		 * 5.当队首进程运行完毕或者用完了时间片,将该进程的needtime减去对应大小，同时cpuTime加上对应大小，并且将其放到队尾
		 * 6.重复4、5过程直到就绪队列为空即模拟完毕
		 */
		
		if(readyQueue.isEmpty()) {
			
			return;
		}
		this.runSet.clear();
		this.runSet=new HashSet<>();
		ProcessPojo pcb=readyQueue.getFirst();//拿到队首pcb
		pcb.setState(ProState.RUN.getState());
		boolean a=runSet.add(pcb);//往运行时队列添加,展示数据
		runPcb(pcb);//模拟运行
		int sec=(int) timeSlice;
		if(sec>pcb.getNeedTime()) {
			sec=(int) pcb.getNeedTime();
		}
		pcb.setCpuTime(pcb.getCpuTime()+sec);//cputime加上相应时间片大小
		pcb.setNeedTime(pcb.getNeedTime()-sec);//needtime减去相应时间片大小
		if(pcb.getNeedTime()<=0) {
			pcb.setState(ProState.FINISH.getState());//设置为运行完成状态
			readyQueue.removeFirst();//将其踢出就绪队列
			System.out.println(pcb.getName()+"-->已经运行完毕..");	
			runSet.add(pcb);
		}
		else {
			//否则将其放到队尾
			readyQueue.removeFirst();
			readyQueue.addLast(pcb);
			pcb.setState(ProState.READY.getState());//修改为就绪状态
			runSet.add(pcb);
		}
		
	}
	public void startMock() {
		/*
		 * 开始模拟
		 * 4.运行就绪队列中对首的进程
		 * 5.当队首进程运行完毕或者用完了时间片,将该进程的needtime减去对应大小，同时cpuTime加上对应大小，并且将其放到队尾
		 * 6.重复4、5过程直到就绪队列为空即模拟完毕
		 */
		while(!readyQueue.isEmpty()) {
			ProcessPojo pcb=readyQueue.getFirst();//拿到队首pcb
			runPcb(pcb);//模拟运行
			pcb.setCpuTime(pcb.getCpuTime()+timeSlice);//cputime加上相应时间片大小
			pcb.setNeedTime(pcb.getNeedTime()-timeSlice);//needtime减去相应时间片大小
			if(pcb.getNeedTime()<=0) {
				pcb.setState(ProState.FINISH.getState());//设置为运行完成状态
				readyQueue.removeFirst();//将其踢出就绪队列
				System.out.println(pcb.getName()+"-->已经运行完毕..");
			}
			else {
				//否则将其放到队尾
				readyQueue.removeFirst();
				readyQueue.addLast(pcb);
			}
			pcb.setState(ProState.READY.getMsg());//修改为就绪状态
		}
		System.out.println("---------------------------------");
		System.out.println("所有进程已经运行完毕！！模拟结束------------------------------");
	}
	
	
	private void runPcb(ProcessPojo pcb) {
		// 模拟运行进程
		String name=pcb.getName();
		int sec=(int) timeSlice;
		if(pcb.getNeedTime()<timeSlice) {
			sec=(int) pcb.getNeedTime();
		}
		System.out.println(name+"正在运行中...");
		System.out.println(name+"-->需要服务时间为"+pcb.getNeedTime()+"  -->当前状态为"+pcb.getState()+" -->cpuTime为"+pcb.getCpuTime());
		
		try {
			TimeUnit.SECONDS.sleep(sec);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	public LinkedList<ProcessPojo> getReadyQueue() {
		return readyQueue;
	}


	public void setReadyQueue(LinkedList<ProcessPojo> readyQueue) {
		this.readyQueue = readyQueue;
	}


	public long getTimeSlice() {
		return timeSlice;
	}


	public void setTimeSlice(long timeSlice) {
		this.timeSlice = timeSlice;
	}


	public static void main(String[] args) {
		RoundRobin rr=new RoundRobin();
		rr.setTimeSlice(2);
		rr.go();
	}

}
